package fr.emse.tatiana.cordtravisualisation;

import java.awt.Color;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Vector;

import org.eclipse.core.resources.IProject;
import org.eclipse.core.runtime.Path;
import org.eclipse.draw2d.Ellipse;
import org.eclipse.draw2d.RectangleFigure;
import org.eclipse.draw2d.RoundedRectangle;
import org.eclipse.draw2d.Triangle;
import org.eclipse.gef.GraphicalViewer;
import org.eclipse.jface.dialogs.Dialog;
import org.eclipse.jface.viewers.ComboViewer;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.IStructuredContentProvider;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.ITableColorProvider;
import org.eclipse.jface.viewers.ITableLabelProvider;
import org.eclipse.jface.viewers.LabelProvider;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.jface.viewers.TableViewer;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.ModifyEvent;
import org.eclipse.swt.events.ModifyListener;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;

import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableColumn;
import org.eclipse.swt.widgets.Text;
import org.eclipse.ui.IEditorInput;
import org.eclipse.ui.IEditorSite;
import org.eclipse.ui.PartInitException;
import org.eclipse.ui.PlatformUI;

import fr.emse.tatiana.display.Ut;
import fr.emse.tatiana.graphical.DisplayRule;
import fr.emse.tatiana.graphical.DisplayRulesParser;
import fr.emse.tatiana.graphical.Octagon;
import fr.emse.tatiana.replayable.AbstractReplayableEditor;
import fr.emse.tatiana.replayable.IGraphicalEditor;
import fr.emse.tatiana.replayable.IReplayableModel;
import fr.emse.tatiana.replayable.IReplayableSaver;
import fr.emse.tatiana.replayable.VisualisationReplayableInput;
import fr.emse.tatiana.replayable.analysis.IAnalysis;

public class CordtraDisplayEditor extends AbstractReplayableEditor implements IGraphicalEditor {

	public static final String ID = "fr.emse.tatiana.CordtraDisplayEditor";

	private String[] rulecolumns = new String[] { "Facet name", "Facet value", "Row", "Shape", "Color"};

//	DisplayRulesParser saver;


	/*
	 * (non-Javadoc)
	 * 
	 * @see fr.emse.tatiana.replayable.AbstractReplayableEditor#addAnalysis(fr.emse.tatiana.replayable.analysis.Analysis)
	 */
	@Override
	public void addAnalysis(IAnalysis a) { // april 2011, Greg thinks this function does nothing that super doesn't already do
		super.addAnalysis(a);
		if (model != null) {
			Object[] rows = model.getAnalysedEvents(a);
			updateViewer(rows);
		}

	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see fr.emse.tatiana.replayable.AbstractReplayableEditor#removeAnalysis(fr.emse.tatiana.replayable.analysis.Analysis)
	 */
	@Override
	public void removeAnalysis(IAnalysis a) {
		super.removeAnalysis(a);
//		rulesviewer.refresh();
//		facetviewer.refresh();
		gde.refresh();
	}

	private VisualisationReplayableInput input;

	private IReplayableModel model;

	public CordtraDisplayEditor() {
		super();
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see fr.emse.tatiana.replayable.AbstractReplayableEditor#init(org.eclipse.ui.IEditorSite,
	 *      org.eclipse.ui.IEditorInput)
	 */
	@Override
	public void init(IEditorSite site, IEditorInput input)
	throws PartInitException {
		super.init(site, input);

		if (input instanceof VisualisationReplayableInput) {
			this.input = (VisualisationReplayableInput) input;
			model = this.input.getDisplayModel(analyses);
			//saver = new DisplayRulesParser(this.input.getFile().getParent().getFile(new Path("."+this.input.getFile().getName()+".scorelayout")),
			//		model);
			this.rules = getDefaultRules();
		} else {
			throw new PartInitException("Bad input for Display");
		}

	}

	List<Boolean> show;
	private List<CordtraRule> getDefaultRules() {
		show = new Vector<Boolean>();
		List<CordtraRule> ret = new Vector<CordtraRule>();
		Map<String,Set<String>> facets = new HashMap<String,Set<String>>();
		int line = 0;
		for (int i = 0; i < model.getFacetCount(); i++) {
			String facetname = model.getFacetName(i);
			Set<String> l = new HashSet<String>();
			for (int e = 0; e < model.getEventCount(); e++) {
				Object event = model.getEvent(e);
				l.add(model.getFacetText(event, i));
			}
			facets.put(facetname,l);
			if (l.size()>20) {
				show.add(i, false);
			} else {
				show.add(i, true);
				int num = 0;
				for (String s: l) {
					System.out.println(s);
					if (l.size()<5) {
						ret.add(new CordtraRule(num+1, CordtraRule.SHAPE, s, facetname));
					} else {
						ret.add(new CordtraRule(1, CordtraRule.SHAPE, s, facetname));
					}
					ret.add(new CordtraRule(getDistinctColor(num, l.size()), CordtraRule.COLOR, s, facetname));
					num++;
				}
				ret.add(new CordtraRule(line*30,CordtraRule.POSITION, null, facetname));
				ret.add(new CordtraRule(0,CordtraRule.VISIBLE, "_",facetname));
				line++;
			}
		}
		return ret;
	}


	private int getDistinctColor(int i, int total) {

		Color c = Color.getHSBColor((float)(1.0*i)/total, 1, 1);

		return (c.getRed() << 16) + (c.getGreen() << 8) + (c.getBlue());
	}
	/*
	 * (non-Javadoc)
	 * 
	 * @see fr.emse.tatiana.replayable.AbstractReplayableEditor#isSaveAsAllowed()
	 */
	@Override
	public boolean isSaveAsAllowed() {
		return false; // don't allow saving as
	}

	@Override
	public IReplayableModel getModel() {
		return model;
	}

	@Override
	public IReplayableSaver getReplayableSaver() {
		return new IReplayableSaver(){

			public void close() {
				// TODO Auto-generated method stub

			}

			public void doSave() {
				// TODO Auto-generated method stub

			}

			public void doSave(String value) {
				// TODO Auto-generated method stub

			}

			public String getName() {
				// TODO Auto-generated method stub
				return null;
			}

			public IProject getProject() {
				// TODO Auto-generated method stub
				return null;
			}

			public boolean hasFile() {
				// TODO Auto-generated method stub
				return false;
			}

			public boolean isSaved() {
				// TODO Auto-generated method stub
				return true;
			}

		};
	}

	@Override
	protected void selectEvents(final StructuredSelection selection,
			final boolean scroll, final boolean propagate) {
		final CordtraDisplayEditor self = this;
		PlatformUI.getWorkbench().getDisplay().syncExec(new Runnable() {
			public void run() {
				try {
					if (!propagate)
						viewer.removeSelectionChangedListener(self);
					gde.setSelection(selection);
				} finally {
					if (!propagate)
						viewer.addSelectionChangedListener(self);
				}
			}
		});

	}

	@Override
	protected void startSynchronisation() {
		viewer.addSelectionChangedListener(this);

	}

	@Override
	protected void endSynchronisation() {
		viewer.removeSelectionChangedListener(this);

	}

	@Override
	protected void updateTitle(int facet, String name) {
//		facetviewer.refresh();
//		rulesviewer.refresh();
	}

	@Override
	protected void updateViewer(Object[] rows) {
		gde.refresh();
//		facetviewer.refresh();
//		rulesviewer.refresh();
	}

	@Override
	protected void createPages() {
		createGraphicalViewer();
		//createLegendViewer();
		//createRulesEditor();
	}

	private void createLegendViewer() {
		Composite c = new Composite(getContainer(), SWT.NONE);
		GridLayout gridLayout = new GridLayout();
		gridLayout.numColumns = 1;
		gridLayout.verticalSpacing = 10;
		gridLayout.marginHeight = 0;
		gridLayout.marginWidth = 0;
		c.setLayout(gridLayout);
		
		TableViewer rowsviewer = new TableViewer(c, SWT.H_SCROLL | SWT.V_SCROLL
				| SWT.BORDER | SWT.FULL_SELECTION);
		Table table = rowsviewer.getTable();
		GridData griddata = new GridData(GridData.FILL, GridData.FILL, true,
				true);
		griddata.horizontalSpan = 1;
		table.setLayoutData(griddata);
		table.setHeaderVisible(true);
		table.setLinesVisible(true);
		for (int i = 0; i < rulecolumns.length; i++) {
			TableColumn column = new TableColumn(table, SWT.LEFT);
			column.setText(rulecolumns[i]);
			column.pack();
		}
		rowsviewer.setColumnProperties(rulecolumns);

		rowsviewer.setContentProvider(new IStructuredContentProvider() {

			public Object[] getElements(Object inputElement) {
				List<Object> l = new Vector<Object>();
				for (CordtraRule rule: rules) {
					if (rule.getProperty().equals(CordtraRule.POSITION)) {
						List<CordtraRule> rl = new Vector<CordtraRule>();
						rl.add(rule);
						l.add(rl);
					}
				}
				for (CordtraRule rule: rules) {
					if (rule.getProperty().equals(CordtraRule.SHAPE)) {
						List<CordtraRule> rl = new Vector<CordtraRule>();
						String facetname = rule.getFacetname();
						String facetvalue = rule.getFacetvalue();
						rl.add(rule);
						for (CordtraRule rule2 : rules) {
							if (rule2.getProperty().equals(CordtraRule.COLOR) &&
									rule2.getFacetname().equals(facetname) && 
									rule2.getFacetvalue().equals(facetvalue)) {
								rl.add(rule2);
							}
						}
						l.add(rl);
					}
				}
				return l.toArray();
			}

			public void dispose() {

			}

			public void inputChanged(Viewer viewer, Object oldInput,
					Object newInput) {
				// pretend we never change the input;
			}

		});
		rowsviewer.setLabelProvider(new RulesLabelProvider());

//		rowsviewer
//		.addSelectionChangedListener(new ISelectionChangedListener() {
//
//			public void selectionChanged(SelectionChangedEvent event) {
//				StructuredSelection sel = (StructuredSelection) rulesviewer
//				.getSelection();
//				currentrule = (sel.isEmpty()) ? null
//						: (DisplayRule) sel.getFirstElement();
//				delete.setEnabled(!sel.isEmpty());
//				edit.setEnabled(!sel.isEmpty());
//			}
//
//		});

		rowsviewer.setInput(rules);

		new Label(c, SWT.NONE).setText(rulecolumns[0]);
		new Label(c, SWT.NONE).setText(rulecolumns[1]);
		new Label(c, SWT.NONE).setText(rulecolumns[2]);
		new Label(c, SWT.NONE).setText(rulecolumns[3]);


		int index = addPage(c);
		setPageText(index, "Visualisation Rules");
		
	}

	@Override
	protected Object getEventFromSelection(Object o) {
		return ((FacetPart) o).getEvent();
	}

	List<CordtraRule> rules;
	private GraphicalViewer viewer;
	private GraphicalDisplayEditor gde;

	protected void createGraphicalViewer() {

		try {
			gde = new GraphicalDisplayEditor(model, rules, show);
			int index = addPage(gde, input);
			setPageText(index, "Replayable");
			viewer = gde.getViewer();
		} catch (PartInitException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

//	private TableViewer rulesviewer;
//	private String[] rulecolumns = new String[] { "Facet", "Facet Value",
//	"Property", "Property Value" };
//	private Button delete;
//	private Button create;
//	private Button edit;
//	private DisplayRule currentrule;
//	protected String facetname;
//	protected String facetvalue;
//	protected String property;
//	protected String propertyvalue;
//	protected ComboViewer facetvalueviewer;
//	protected ComboViewer facetviewer;

//	protected void createRulesEditor() {
//	Composite c = new Composite(getContainer(), SWT.NONE);

//	GridLayout gridLayout = new GridLayout();
//	gridLayout.numColumns = 4;
//	gridLayout.verticalSpacing = 10;
//	gridLayout.marginHeight = 0;
//	gridLayout.marginWidth = 0;
//	c.setLayout(gridLayout);

//	rulesviewer = new TableViewer(c, SWT.H_SCROLL | SWT.V_SCROLL
//	| SWT.BORDER | SWT.FULL_SELECTION);
//	Table table = rulesviewer.getTable();
//	GridData griddata = new GridData(GridData.FILL, GridData.FILL, true,
//	true);
//	griddata.horizontalSpan = 4;
//	table.setLayoutData(griddata);
//	table.setHeaderVisible(true);
//	table.setLinesVisible(true);
//	for (int i = 0; i < rulecolumns.length; i++) {
//	TableColumn column = new TableColumn(table, SWT.LEFT);
//	column.setText(rulecolumns[i]);
//	column.pack();
//	}
//	rulesviewer.setColumnProperties(rulecolumns);

//	rulesviewer.setContentProvider(new IStructuredContentProvider() {

//	public Object[] getElements(Object inputElement) {
//	return rules.toArray();
//	}

//	public void dispose() {

//	}

//	public void inputChanged(Viewer viewer, Object oldInput,
//	Object newInput) {
//	// pretend we never change the input;
//	}

//	});
//	rulesviewer.setLabelProvider(new RulesLabelProvider());

//	rulesviewer
//	.addSelectionChangedListener(new ISelectionChangedListener() {

//	public void selectionChanged(SelectionChangedEvent event) {
//	StructuredSelection sel = (StructuredSelection) rulesviewer
//	.getSelection();
//	currentrule = (sel.isEmpty()) ? null
//	: (DisplayRule) sel.getFirstElement();
//	delete.setEnabled(!sel.isEmpty());
//	edit.setEnabled(!sel.isEmpty());
//	}

//	});

//	rulesviewer.setInput(rules);

//	new Label(c, SWT.NONE).setText(rulecolumns[0]);
//	new Label(c, SWT.NONE).setText(rulecolumns[1]);
//	new Label(c, SWT.NONE).setText(rulecolumns[2]);
//	new Label(c, SWT.NONE).setText(rulecolumns[3]);

//	facetviewer = new ComboViewer(c);
//	facetviewer.setContentProvider(new IStructuredContentProvider() {

//	public Object[] getElements(Object inputElement) {
//	if (inputElement == null) {
//	return new Object[] {};
//	}
//	IReplayableModel model = (IReplayableModel) inputElement;
//	List<String> ret = new Vector<String>();
//	ret.add("Any");
//	for (int i = 0; i < model.getFacetCount(); i++) {
//	ret.add(model.getFacetName(i));
//	}
//	return ret.toArray();
//	}

//	public void dispose() {
//	}

//	public void inputChanged(Viewer viewer, Object oldInput,
//	Object newInput) {
//	}

//	});

//	facetviewer
//	.addSelectionChangedListener(new ISelectionChangedListener() {
//	public void selectionChanged(SelectionChangedEvent event) {
//	String elem = (String) ((IStructuredSelection) event
//	.getSelection()).getFirstElement();
//	if ("Any".equals(elem)) {
//	facetname = null;
//	} else {
//	facetname = elem;
//	}
//	facetvalueviewer.refresh();
//	}
//	});

//	facetviewer.setInput(model);

//	facetvalueviewer = new ComboViewer(c);

//	facetvalueviewer.setContentProvider(new IStructuredContentProvider() {

//	public Object[] getElements(Object inputElement) {
//	if (inputElement == null) {
//	return new Object[] {};
//	}
//	IReplayableModel model = (IReplayableModel) inputElement;
//	Set<String> ret = new HashSet<String>();
//	for (int e = 0; e < model.getEventCount(); e++) {
//	Object event = model.getEvent(e);
//	if (facetname == null) {
//	for (int i = 0; i < model.getFacetCount(); i++) {
//	String s = model.getFacetText(event, i);
//	ret.add((s != null && s.length() > 50) ? s
//	.substring(0, 50)
//	+ "..." : s);
//	} // TODO don't do this here, do it in a label provider
//	} else {
//	String s = model.getFacetText(event, model.getFacetCol(facetname));
//	ret.add((s != null && s.length() > 50) ? s.substring(0,
//	50)
//	+ "..." : s);
//	}
//	}
//	List<String> l = new LinkedList<String>(ret);
//	if (l.contains(null)) {
//	l.remove(null);
//	}
//	java.util.Collections.sort(l);
//	l.add(0, "Any");
//	return l.toArray();
//	}

//	public void dispose() {
//	}

//	public void inputChanged(Viewer viewer, Object oldInput,
//	Object newInput) {
//	}

//	});

//	facetvalueviewer
//	.addSelectionChangedListener(new ISelectionChangedListener() {
//	public void selectionChanged(SelectionChangedEvent event) {
//	String elem = (String) ((IStructuredSelection) event
//	.getSelection()).getFirstElement();
//	if ("Any".equals(elem)) {
//	facetvalue = null;
//	} else {
//	facetvalue = elem;
//	}
//	}
//	});

//	facetvalueviewer.setInput(model);

//	final ComboViewer propertyviewer = new ComboViewer(c);
//	propertyviewer.setContentProvider(new IStructuredContentProvider() {

//	public Object[] getElements(Object inputElement) {
//	return DisplayRule.properties;
//	}

//	public void dispose() {
//	}

//	public void inputChanged(Viewer viewer, Object oldInput,
//	Object newInput) {
//	}

//	});

//	propertyviewer
//	.addSelectionChangedListener(new ISelectionChangedListener() {
//	public void selectionChanged(SelectionChangedEvent event) {
//	String elem = (String) ((IStructuredSelection) event
//	.getSelection()).getFirstElement();
//	property = elem;
//	}
//	});

//	propertyviewer.setInput(new Object());

//	final Text propertyvaluew = new Text(c, SWT.BORDER);

//	propertyvaluew.addModifyListener(new ModifyListener() {
//	public void modifyText(ModifyEvent e) {
//	propertyvalue = ((Text) e.getSource()).getText();

//	}
//	});

//	create = new Button(c, SWT.PUSH);
//	create.setText("Create Rule");
//	create.addSelectionListener(new SelectionListener() {

//	public void widgetDefaultSelected(SelectionEvent e) {
//	// doesn't happen
//	}

//	public void widgetSelected(SelectionEvent e) {
//	createRule();
//	}
//	});

//	delete = new Button(c, SWT.PUSH);
//	delete.setText("Delete Selected Rule");
//	delete.addSelectionListener(new SelectionListener() {

//	public void widgetDefaultSelected(SelectionEvent e) {
//	// doesn't happen
//	}

//	public void widgetSelected(SelectionEvent e) {
//	deleteRule();
//	}
//	});
//	delete.setEnabled(false);



////	edit = new Button(c,SWT.PUSH);
////	edit.setText("Edit Selected Rule");
////	edit.addSelectionListener(new SelectionListener(){

////	public void widgetDefaultSelected(SelectionEvent e) {
////	// TODO Auto-generated method stub

////	}

////	public void widgetSelected(SelectionEvent e) {
////	// TODO Auto-generated method stub	
////	EditRuleDialog dialog=new EditRuleDialog(PlatformUI.getWorkbench().getDisplay().getActiveShell(),model,currentrule.getFacet(),currentrule.getFacetvalue(),currentrule.getProperty(),currentrule.getPropertyvalue());

////	if(!(dialog.open()==0)){
////	return;
////	}
////	if (rules.contains(currentrule))
////	rules.remove(currentrule);
////	rules.add(new DisplayRule(dialog.facetname,dialog.facetvalue, dialog.property, dialog.propertyvalue));
////	touchRules();
////	rulesviewer.refresh();
////	gde.refresh();
////	}

////	});
////	edit.setEnabled(false);


//	int index = addPage(c);
//	setPageText(index, "Visualisation Rules");
//	}

//	protected void deleteRule() {
//	if (rules.contains(currentrule))
//	rules.remove(currentrule);
//	touchRules();
//	rulesviewer.refresh();
//	gde.refresh();
//	}

//	protected void createRule() {
//	//rules.add(new DisplayRule(facetname, facetvalue, property, propertyvalue));
//	touchRules();
//	rulesviewer.refresh();
//	gde.refresh();
//	}

//	private class RulesLabelProvider extends LabelProvider implements
//	ITableLabelProvider {

//	public Image getColumnImage(Object element, int columnIndex) {
//	return null;
//	}

//	public String getColumnText(Object element, int columnIndex) {
//	DisplayRule rule = (DisplayRule) element;
//	switch (columnIndex) {
//	case 0:
//	try {
//	return (rule.getFacet() == null) ? "Any" : rule.getFacet();
//	} catch (Exception e) {
//	return "facet "+rule.getFacet(); // probably not needed
//	}
//	case 1:
//	return (rule.getFacetvalue() == null) ? "Any" : rule
//	.getFacetvalue();
//	case 2:
//	return (rule.getProperty() == null) ? "Any" : rule
//	.getProperty();
//	case 3:
//	default:
//	return (rule.getPropertyvalue() == null) ? "$"
//	+ getColumnText(element, 0) : rule.getPropertyvalue()
//	.toString();
//	}
//	}

//	}

	protected void touchRules() {
		//saver.touch();
		firePropertyChange(PROP_DIRTY);
	}

	public GraphicalViewer getViewer() {
		return viewer;
	}
	
	private class RulesLabelProvider extends LabelProvider implements
	ITableLabelProvider, ITableColorProvider {

		public Image getColumnImage(Object element, int columnIndex) {
			return null;
		}

		public String getColumnText(Object element, int columnIndex) {
			List<CordtraRule> rules = (List<CordtraRule>) element;
			CordtraRule fstrule = rules.get(0);
			switch (columnIndex) {
			case 0:
				return fstrule.getFacetname();
			case 1:
				return (rules.size()==1) ? "Any" : fstrule.getFacetvalue();
			case 2:
				if (rules.size()==1) {
					return "" + (fstrule.getCurrentvalue()/30);
				} else {
					return "";
				}
			case 3:
				if (rules.size()>1) {
					switch (fstrule.getCurrentvalue()) {
					case 1:
						return "circle";
					case 2:
						return "square";
					case 3:
						return "rounded square";
					case 4:
						return "triangle";
					case 5:
						return "octogon";

					case 0:
					default:
						return "";
					}
				} else {
					return "";
				}
			case 4:
			default:
				return "";
			}
		}

		public org.eclipse.swt.graphics.Color getBackground(Object element,
				int columnIndex) {
			List<CordtraRule> rules = (List<CordtraRule>) element;
			if (columnIndex==4 && rules.size()>1) {
				return rules.get(1).getCurrentColor();
			}
			return null;
		}

		public org.eclipse.swt.graphics.Color getForeground(Object element,
				int columnIndex) {
			// TODO Auto-generated method stub
			return null;
		}

	}


}


